package com.harry.basis;

import java.beans.PropertyDescriptor;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.BeanUtils;

import com.harry.configuration.poentity.PoVali;
import com.harry.utility.PoEntityHelper;

/**
 * 一个实体的业务配置，用于与前端/第三方系统统一集中管理业务
 */
public abstract class PropertySettings<T extends BasePoEntity> extends PureGeneric<T> {

	private final Map<String, PoVali> name_vali_map = new LinkedHashMap<String, PoVali>();

	private Map<String, Map<String, Object>> perm_action_ctxKey_ctxValue_map = new LinkedHashMap<>();

	private Map<String, Map<String, Object>> admin_action_ctxKey_ctxValue_map = new LinkedHashMap<>();

	public PropertySettings() {
		nameValiSettings(name_vali_map);
		permSettings(perm_action_ctxKey_ctxValue_map);
		adminSettings(admin_action_ctxKey_ctxValue_map);
	}

	// 1. For Outline
	public abstract String[] nameProperties();

	// 2. For Searching By Keywords
	public abstract String[] keyProperties();

	// 3. For List Function
	public abstract String[] listProperties();

	// 4. For Edit Function
	public abstract String[] editProperties();

	// 5. For Add Function
	public abstract String[] addProperties();

	// 6. For Criteria Function ( Filter For List )
	public abstract String[] criteriaProperties();

	// 7. For List Group Labels
	public abstract String[] listLabels();

	// 8. For List Group Splits
	public abstract Integer[] listIndexes();

	// 9. For Edit Group Labels
	public abstract String[] editLabels();

	// 10. For Edit Group Splits
	public abstract Integer[] editIndexes();

	// 11. For Add Group Labels
	public abstract String[] addLabels();

	// 12. For Add Group Splits
	public abstract Integer[] addIndexes();

	// 13. For Criteria Group Labels
	public abstract String[] criteriaLabels();

	// 14. For Criteria Group Splits
	public abstract Integer[] criteriaIndexes();

	/**
	 * "bool": nullable
	 * 
	 * "date": nullable, maxDate, minDate
	 * 
	 * "dict": nullable
	 * 
	 * "oref": nullable
	 * 
	 * "file": nullable
	 * 
	 * "nmbr": nullable, maxNmbr, minNmbr
	 * 
	 * "pswd": nullable, maxLen, minLen, password
	 * 
	 * "txea": nullable, maxLen, minLen
	 * 
	 * "text": nullable, maxLen, minLen
	 * 
	 * "[izArray==true]": maxSize, minSize
	 * 
	 * @param pd
	 */
	public void nameValiSettings(Map<String, PoVali> name_vali_map) {
		if (this.getEntityClass() != null) {
			PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(this.getEntityClass());
			for (PropertyDescriptor pd : pds) {
				if (pd.getWriteMethod() != null && pd.getReadMethod() != null) {
					name_vali_map.put(pd.getName(),
							PoEntityHelper.createValiByFieldDeclaring(this.getEntityClass(), pd.getName()));
				}
			}
		}
	};

	public void permSettings(Map<String, Map<String, Object>> perm_map) {
	}

	public void adminSettings(Map<String, Map<String, Object>> admin_map) {
	}

	public String[] publicActions() {
		return null;
	}

	public String getOrefType() {
		return getEntityClass().getSimpleName();
	}

	public String[] allFields() {
		Set<String> ignores = Stream.of(BeanUtils.getPropertyDescriptors(BasePoEntity.class)).map(pd -> pd.getName())
				.collect(Collectors.toSet());
		Set<String> propertySet = Stream.of(BeanUtils.getPropertyDescriptors(getEntityClass())).map(pd -> pd.getName())
				.filter(s -> !ignores.contains(s)).collect(Collectors.toSet());
		Object[] properties = Stream.of(getEntityClass().getDeclaredFields()).map(f -> f.getName())
				.filter(n -> propertySet.contains(n)).toArray();
		return ArrayUtils.toStringArray(properties);
	}

	public Map<String, PoVali> nameValiSettings() {
		return name_vali_map;
	};

	public Map<String, Map<String, Object>> permSettings() {
		return perm_action_ctxKey_ctxValue_map;
	}

	public Map<String, Map<String, Object>> adminSettings() {
		return admin_action_ctxKey_ctxValue_map;
	}
}
